﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using ResxLocalizationEditor.GoogleImport;
using ResxLocalizationEditor.GoogleExport;

namespace ResxLocalizationEditor {
	public partial class MainForm : Form {
		
		public MainForm() {
			InitializeComponent();
		}

		bool _editing = false;

		public bool Editing {
			get {
				return _editing;
			}
			set {
				_editing = value;

				//Gui
				menuAddRow.Enabled = value;
				menuAddLanguage.Enabled = value;
			}
		}

		#region GUI events

		protected override void OnClosing(CancelEventArgs e) {
			if (_resources != null && _resources.HasChanged) {
				var ret = MessageBox.Show("The open resources have pending changes. Do you want to save changes before closing?", "Save changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Hand);

				switch (ret) {
					case DialogResult.Yes:
						if (!SaveResources(_resources.OriginalResourcePath)) {
							e.Cancel = true;
							return;
						}
						break;

					case DialogResult.Cancel:
						e.Cancel = true;
						return;
				}
			}

			base.OnClosing(e);
		}

		private void Menu_File_opening(object sender, EventArgs e) {
			menuSave.Enabled = _editing;
			menuSaveAs.Enabled = _editing;
			menuClose.Enabled = _editing;
            menuExportCsv.Enabled = _editing;
            menuExportGoogle.Enabled = _editing;
		}

		private void Menu_Load_click(object sender, EventArgs e) {
			using (var dlg = new OpenFileDialog()) {
				dlg.Filter = "Resource file (*.resx)|*.resx";

				if (dlg.ShowDialog(this) == DialogResult.OK) {
					if(LoadResources(dlg.FileName))
						PopulateDataGrid(_resources);
				}
			}
		}

		private void Menu_Save_click(object sender, EventArgs e) {
			SaveResources(_resources.OriginalResourcePath);
		}

		private void Menu_SaveAs_click(object sender, EventArgs e) {
			using (var dlg = new SaveFileDialog()) {
				dlg.Filter = "Resource file (*.resx)|*.resx";
				dlg.OverwritePrompt = true;
				dlg.AddExtension = true;

				if (dlg.ShowDialog(this) == DialogResult.OK) {
					SaveResources(dlg.FileName);

					_resources.OriginalResourcePath = dlg.FileName;
				}
			}
		}

        private void Menu_Export_click(object sender, EventArgs e) {
            using (var dlg = new SaveFileDialog()) {
                dlg.Filter = "Comma Separated File (*.csv)|*.csv";
                dlg.OverwritePrompt = true;
                dlg.AddExtension = true;

                if (dlg.ShowDialog(this) == DialogResult.OK) {
                    ExportResources(dlg.FileName);
                }
            }
        }

        private void Menu_LoadFromGoogleDocs_click(object sender, EventArgs e) {
            using (var dlg = new GoogleDocsImport()) {
                dlg.ShowDialog(this);

                if (dlg.ImportedResourceSet != null) {
                    _resources = dlg.ImportedResourceSet;
                    PopulateDataGrid(_resources);
                }
            }
        }

        private void Menu_ExportToGoogleDocs_click(object sender, EventArgs e) {
            using (var dlg = new GoogleDocsExport(_resources)) {
                dlg.ShowDialog(this);
            }
        }

		private void Menu_Close_click(object sender, EventArgs e) {
			CloseResources();
		}

		private void Menu_Quit_click(object sender, EventArgs e) {
			this.Close();
		}

		private void Menu_AddRow_click(object sender, EventArgs e) {
			AddRow();
		}

		private void Menu_RemoveRow_click(object sender, EventArgs e) {
			if (_dataGrid.SelectedCells.Count >= 1) {
				var keyName = _dataGrid.SelectedCells[0].OwningRow.Cells[0].Value as string;

				RemoveRow(_dataGrid.SelectedCells[0].OwningRow.Index, keyName);
			}
		}

		private void Menu_AddLanguage_click(object sender, EventArgs e) {
			AddLanguage();
		}

		private void Menu_RemoveLanguage_click(object sender, EventArgs e) {
			if (_dataGrid.SelectedCells.Count >= 1) {
				var langName = (CultureInfo)_dataGrid.SelectedCells[0].OwningColumn.Tag;

				RemoveLanguage(_dataGrid.SelectedCells[0].OwningColumn.Index, langName);
			}
		}

		private void DataGrid_Selection_change(object sender, EventArgs e) {
			if (_dataGrid.SelectedCells.Count == 0) {
				menuRemoveRow.Enabled = false;
				menuRemoveLanguage.Enabled = false;

				textEditor.Enabled = false;
			}
			else {
				menuRemoveRow.Enabled = true;
				menuRemoveLanguage.Enabled = (_dataGrid.SelectedCells[0].ColumnIndex != 0);

				textEditor.Text = _dataGrid.SelectedCells[0].Value as string;
				textEditor.Enabled = true;
			}
		}

		private void DataGrid_Value_change(object sender, DataGridViewCellEventArgs e) {
			if (!_editing)
				return;

			var newValue = _dataGrid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value as string;

            if (e.ColumnIndex == 0) {
                //Key renaming
                ChangeKey(e.RowIndex, newValue);
            }
            else{
                var row = _dataGrid.Rows[e.RowIndex];
                var rowName = row.Cells[0].Value as string;

                if (e.ColumnIndex == _dataGrid.Columns.Count - 1) {
                    //Comment change
                    ChangeComment(rowName, newValue);
                }
                else {
                    //Value change
                    var col = _dataGrid.Columns[e.ColumnIndex];
                    ChangeValue((CultureInfo)col.Tag, rowName, newValue);
                }
            }
		}

		private void TextEditor_EditingComplete(object sender, EventArgs e) {
			PerformCellUpdate();
		}

		private void TextEditor_MoveCommand(object sender, MoveEventArgs e) {
			if (_dataGrid.SelectedCells.Count > 0) {
				var cell = _dataGrid.SelectedCells[0];
				var iRow = cell.OwningRow.Index;
				var iCol = cell.OwningColumn.Index;

				switch (e.MoveDirection) {
					case Direction.Up:
						_dataGrid.CurrentCell = _dataGrid.Rows[Math.Max(0, iRow - 1)].Cells[iCol];
						break;

					case Direction.Down:
						_dataGrid.CurrentCell = _dataGrid.Rows[Math.Min(_dataGrid.Rows.Count - 1, iRow + 1)].Cells[iCol];
						break;

					case Direction.Right:
						_dataGrid.CurrentCell = _dataGrid.Rows[iRow].Cells[Math.Min(_dataGrid.Columns.Count - 1, iCol + 1)];
						break;

					case Direction.Left:
						_dataGrid.CurrentCell = _dataGrid.Rows[iRow].Cells[Math.Max(0, iCol - 1)];
						break;
				}
			}
		}

		#endregion

		private void PerformCellUpdate() {
			if (_dataGrid.SelectedCells.Count > 0) {
				var cell = _dataGrid.SelectedCells[0];

				cell.Value = textEditor.Text;
			}
		}

		ResourceSet _resources = null;

		private bool LoadResources(string resourcePath) {
			try {
				_statusLabel.Text = "Loading resources...";

				_resources = new ResourceSet(resourcePath, new ResxResourceWriter());

				_statusLabel.Text = "Loaded " + _resources.TotalNumberOfKeys + " keys.";

				return true;
			}
			catch (Exception ex) {
				_statusLabel.Text = "Error loading resources.";

				MessageBox.Show("Error loading resources:\n" + ex.Message);

				return false;
			}
		}

		private bool SaveResources(string resourcePath) {
			try {
				_statusLabel.Text = "Saving resources...";

				_resources.ExportSetToFile(resourcePath, new ResxResourceWriter());

				_statusLabel.Text = "Resources saved.";

				return true;
			}
			catch (Exception ex) {
				_statusLabel.Text = "Error saving resources.";

				MessageBox.Show("Error saving resources:\n" + ex.Message);

				return false;
			}
		}

        private bool ExportResources(string path) {
            try {
                _statusLabel.Text = "Exporting...";

                _resources.ExportSetToFile(path, new CsvResourceWriter());

                _statusLabel.Text = "Resources exported.";

                return true;
            }
            catch (Exception ex) {
                _statusLabel.Text = "Error while exporting resources.";
                MessageBox.Show("Error saving resources:\n" + ex.ToString());
                return false;
            }
        }

		private void CloseResources() {
			_resources = null;

			//GUI and state
			Editing = false;
			ClearDataGrid();

			_statusLabel.Text = "Resource files closed.";
		}

		private DataGridViewTextBoxColumn CreateColumn(CultureInfo lang) {
			return new DataGridViewTextBoxColumn {
				AutoSizeMode = DataGridViewAutoSizeColumnMode.None,
                HeaderText = (lang == null) ? "Default" : string.Format("{0} ({1})", lang.EnglishName, lang.Name),
                Name = "lang" + lang,
				Resizable = DataGridViewTriState.True,
                Tag = lang
			};
		}

        /// <summary>
        /// Repopulates the data grid using a resource set.
        /// </summary>
        /// <param name="resources">The resource set to get data from.</param>
		private void PopulateDataGrid(ResourceSet resources) {
			ClearDataGrid();

			_dataGrid.Enabled = true;

            var langs = (from l in _resources.Languages orderby l.Name select l).ToArray();
            int numLanguages = langs.Length;

            //Create columns
			for(int i = 0; i < numLanguages; ++i){
				_dataGrid.Columns.Insert(i + 1, CreateColumn(langs[i]));
			}

			//Create rows (values and comments)
			foreach (var key in _resources.Keys) {
				var values = new object[numLanguages + 2];
				values[0] = key;
				for(int i = 0; i < numLanguages; ++i)
					values[i + 1] = _resources.GetStringValue(key, langs[i]);
                values[numLanguages + 1] = _resources.GetComment(key);

				_dataGrid.Rows.Add(values);
			}

			_dataGrid.Update();
			
			Editing = true;
		}

		private void ClearDataGrid() {
			_dataGrid.Rows.Clear();

			//Remove all columns except key and column
            var colsToRemove = (from col in _dataGrid.Columns.Cast<DataGridViewColumn>()
                                where !col.Equals(CommentColumn) && !col.Equals(KeyColumn)
                                select col).ToArray();
            foreach (var col in colsToRemove)
                _dataGrid.Columns.Remove(col);
		}

		private void ChangeValue(CultureInfo lang, string rowName, string newValue) {
			_resources.SetStringValue(rowName, lang, newValue);

			_statusLabel.Text = "Values for key " + rowName + " updated.";
		}

        private void ChangeComment(string rowName, string newValue) {
            _resources.SetComment(rowName, newValue);

            _statusLabel.Text = "Comment for key " + rowName + " updated.";
        }

		private void ChangeKey(int index, string newValue) {
			var oldValue = _resources.Keys[index];

            try {
                _resources.RenameKey(oldValue, newValue);

                _statusLabel.Text = "Key " + oldValue + " renamed to " + newValue + ".";
            }
            catch (ArgumentException ex) {
                MessageBox.Show(ex.Message, "Failed to rename.");
            }
		}

		private void AddRow() {
			var dlg = new KeyNameDialog();
			if (dlg.ShowDialog(this) == DialogResult.OK) {
				var keyName =  dlg.RowName.Text;

				if (string.IsNullOrEmpty(keyName)) {
					MessageBox.Show("Error, cannot add (null/empty reference).");
					return;
				}

				try {
					_resources.AddKey(keyName);

					_dataGrid.Rows.Add(keyName);

					_statusLabel.Text = "Key " + keyName + " added.";
				}
				catch (Exception ex) {
					MessageBox.Show("Cannot add row:\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
		}

		private void RemoveRow(int gridIndex, string keyName) {
			if (string.IsNullOrEmpty(keyName)) {
				MessageBox.Show("Error, cannot remove (null/empty reference).");
				return;
			}

			if (MessageBox.Show(this, "Remove key '" + keyName + "'?", "Confirm delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
				_resources.RemoveKey(keyName);

				_dataGrid.Rows.RemoveAt(gridIndex);

				_statusLabel.Text = "Key " + keyName + " removed.";
			}
		}

		private void AddLanguage() {
			using (var dlg = new AddLanguageEditor()) {
				if (dlg.ShowDialog(this) == DialogResult.OK) {
					try {
						_resources.AddLanguage(dlg.SelectedCultureCode);

						_dataGrid.Columns.Insert(1, (CreateColumn(dlg.SelectedCultureCode)));
					}
					catch (Exception ex) {
						MessageBox.Show("Cannot add language:\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					}
				}
			}
		}

		private void RemoveLanguage(int colIndex, CultureInfo lang) {
            if (MessageBox.Show(this, "Remove language '" + lang + "'?", "Confirm delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
                _resources.RemoveLanguage(lang);

				_dataGrid.Columns.RemoveAt(colIndex);

                _statusLabel.Text = "Language " + lang + " removed.";
			}
		}

	}
}
